package org.lee.bmh;

import org.openjdk.jmh.annotations.*;

import java.util.concurrent.TimeUnit;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * SummaryNumber
 *
 * @author dralee
 * @BenchmarkMode： 测试类型，有以下几种可选：
 * Throughput：吞吐量，即每秒执行可多少次。
 * AverageTime：平均时间，即每次调用平均耗时。
 * SampleTime：随机取样。
 * SingleShotTime：顾名思义，只运行一次，一般用于测试冷启动性能。
 * All：
 * @Warmup：预热，一般为保证测试准确性，要预热几次。
 * @Measurement：测量。 iterations：测试多少轮。
 * time：每轮时长。
 * timeUnit：时间单位。
 * @Fork：JMH fork出指定个数的进程测试。
 * @Threads：每个测试进程的测试线程数量。
 * @OutputTimeUnit：测试结果的时间单位。
 * @Benchmark：标记某个方法进行基准测试，类比JUnit的@Test。
 * @Param：指定同一个方法的不同参数。
 * @State：标记某对象在指定Scope内共享，通过@Benchmark标记的方法参数注入，Scope分三种： <p></p>
 * · Benchmark，所有线程共享实例。
 * · Group，线程组内共享实例。
 * · Thread，线程内共享实例。
 * @Setup：配置了@State的类专用，类比JUnit的@Setup，在benchmark方法执行前state实例做的操作。
 * @TearDown：配置了@State的类专用，类比JUnit的@TearDown，在benchmark方法执行后state实例做的操作。
 * @date 2022-01-24 14:41:05
 **/
@BenchmarkMode(Mode.AverageTime)  // Throughput
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@State(Scope.Thread)
@Fork(value = 2, jvmArgs = {"-Xms4G", "-Xmx4G"}) // 4G
public class SummaryNumber {

    private static final int N = 40;

    @Benchmark
    public long sequentialStreamSum() {
        return Stream.iterate(1L, i -> i + 1).limit(N).reduce(0L, Long::sum);
    }

    @Benchmark
    public long parallelStreamSum() {
        return Stream.iterate(1L, i -> i + 1).limit(N).parallel().reduce(0L, Long::sum);
    }

    @Benchmark
    public long sequentialStreamRangeSum() {
        return LongStream.rangeClosed(1L, N).sum();
    }

    @Benchmark
    public long parallelStreamRangeSum() {
        return LongStream.rangeClosed(1L, N).parallel().sum();
    }

    /**
     * 装箱和拆箱操作引入不少开销。使用Stream<Long>（而非LongStream）的parallelStreamSum和sequentialStreamSum操作非常慢，加之由iterate方法产生的数据集合不易分解，速度问题更加突出
     * LongStream.rangeClosed方法则快得多，sequentialStreamRangeSum和parallelStreamRangeSum操作在性能上几乎没差别
     *
     * 利用 JHM 对 1000 万个元素（N = 10,000,000）进行测试
     *Benchmark                               Mode  Cnt   Score   Error  Units
     * SummaryNumber.parallelStreamRangeSum    avgt   10  16.582 ± 1.642  us/op
     * SummaryNumber.parallelStreamSum         avgt   10  40.132 ± 1.234  us/op
     * SummaryNumber.sequentialStreamRangeSum  avgt   10   0.105 ± 0.007  us/op
     * SummaryNumber.sequentialStreamSum       avgt   10   0.393 ± 0.012  us/op
     */
}
